import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.Socket;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Enumeration;

import java.util.List;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory;


public class CRLGossip implements Runnable{

	private static final int DEFAULT_PORT = 7777;

	private static final String KEY_STORE_PASSWORD = "123456";
	private static final String TRUST_KEY_STORE_PASSWORD = "123456";

	private String localIP;
	
	private SSLSocket sslSocket;
	private List<Principal> principalList;
	
	private SSLContext ctx;
	private SSLServerSocket serverSocket;
	
	public CRLGossip(){
		this.principalList = new ArrayList<Principal>();
		this.localIP = getIPAddress().toString().split("/")[1];
		getMemberList();
		init();
		
	}
	
	private void init() {
		try {
			this.ctx = SSLContext.getInstance("SSL");

			KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
			TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

			KeyStore ks = KeyStore.getInstance("JKS");
			KeyStore tks = KeyStore.getInstance("JKS");

			ks.load(new FileInputStream("node_a_keystore.jks"),
					KEY_STORE_PASSWORD.toCharArray());
			tks.load(new FileInputStream("ca_keystore.jks"),
					TRUST_KEY_STORE_PASSWORD.toCharArray());

			kmf.init(ks, KEY_STORE_PASSWORD.toCharArray());
			tmf.init(tks);

			this.ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private InetAddress getIPAddress() {
        try {
            for (Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements();) {
                NetworkInterface networkInterface = interfaces.nextElement();
                if (networkInterface.isLoopback() || networkInterface.isVirtual() || !networkInterface.isUp()) {
                    continue;
                }
                Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
                if (addresses.hasMoreElements()) {
                    return addresses.nextElement();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }
	
	
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		CRLGossip crlGossip = new CRLGossip();
		new Thread(crlGossip).start();
		crlGossip.scan();
		crlGossip.gossip();
		//this.sslSocket = (SSLSocket) ctx.getSocketFactory().createSocket(DEFAULT_HOST, DEFAULT_PORT);
		

	}
	
	
	public void scan(){
		
	}
	public void gossip(){
		
	}
	
	
	
	public void getMemberList() {
		
		String fileName = "memberList";

		try {
			 List<String> memberList = Files.readAllLines(Paths.get(fileName),Charset.defaultCharset());
			for (String line : memberList) {
				if (!(line.equals(this.localIP))) {
					System.out.println(line);
					Principal p = new Principal(line);
					this.principalList.add(p);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void run() {
		try{
		this.serverSocket = (SSLServerSocket) this.ctx.getServerSocketFactory().createServerSocket(DEFAULT_PORT);
		}catch (Exception ex){
			ex.printStackTrace();
		}
		if (serverSocket == null) {
			System.out.println("ERROR");
			System.exit(0);
		}
		this.serverSocket.setNeedClientAuth(true);
		System.out.println("Server thread is up and running");
		while (true) {
			try {
				Socket s = serverSocket.accept();
				System.out.println("Server thread received a new connection");
				InputStream is = null;
				is = s.getInputStream();
				ByteArrayOutputStream baos = new ByteArrayOutputStream();
				byte[] aByte = new byte[1];
				int bytesRead;
				if (is != null) {

					FileOutputStream fos = null;
					BufferedOutputStream bos = null;
					try {
						fos = new FileOutputStream("receive");
						bos = new BufferedOutputStream(fos);
						bytesRead = is.read(aByte, 0, aByte.length);

						do {
							baos.write(aByte);
							bytesRead = is.read(aByte);
						} while (bytesRead != -1);

						bos.write(baos.toByteArray());
						System.out.println("received: " + baos.size());
						bos.flush();
						bos.close();
						
					} catch(SSLException sslex){
						System.out.println("SSL required");
						
					}
					catch (IOException ex) {
						System.err.println(ex.toString());
						ex.printStackTrace();
					}
				}

				s.close();
			} catch (Exception e) {
				
				e.printStackTrace();
				
			}
		}
		
	}

}
